﻿namespace ScrumLite.Services.Tests
{
    using System;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using ScrumLite.Services.Contracts;
    using Rhino.Mocks;
    using System.Collections.Generic;
    using System.Globalization;

    [TestClass]
    public class LinqReviewsServiceFixture
    {
        MockRepository mocks;
        [TestInitialize]
        public void Initialize()
        {
            this.mocks = new MockRepository();
        }

        [TestMethod()]
        public void ShouldAddReview()
        {
            ScrumLite.Data.IReviewStore store = this.mocks.DynamicMock<ScrumLite.Data.IReviewStore>();
            ScrumLite.Data.Review actual = null;

            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(() => store.Add(null))
                .Callback(new Func<ScrumLite.Data.Review, bool>(r => { actual = r; return true; }));
            mocks.ReplayAll();

            LinqReviewsService service = new LinqReviewsService(store);
            
            Guid projectId = Guid.NewGuid();
            Review expected = new Review() { ProjectId = projectId , OccurredOn = DateTime.Now, ConductedBy = "Auditor", EvidenceUrl = "http://some_url" };
            service.AddReview(expected);

            Assert.AreNotEqual(Guid.Empty, actual.id);
            Assert.AreEqual(expected.ProjectId, actual.fk_project);
            Assert.AreEqual(expected.OccurredOn, actual.occuredOn);
            Assert.AreEqual(expected.ConductedBy, actual.conductedBy);
            Assert.AreEqual(expected.EvidenceUrl, actual.uri_evidence);
        }

        [TestMethod()]
        public void ShouldUpdateReview()
        {
            ScrumLite.Data.IReviewStore store = this.mocks.DynamicMock<ScrumLite.Data.IReviewStore>();
            ScrumLite.Data.Review actual = null;

            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(() => store.Update(null))
                .Callback(new Func<ScrumLite.Data.Review, bool>(r => { actual = r; return true; }));
            mocks.ReplayAll();

            LinqReviewsService service = new LinqReviewsService(store);

            Guid projectId = Guid.NewGuid();
            Review expected = new Review() { Id = Guid.NewGuid(), ProjectId = projectId, OccurredOn = DateTime.Now, ConductedBy = "Auditor", EvidenceUrl = "http://some_url" };
            service.UpdateReview(expected);

            Assert.AreEqual(expected.Id, actual.id);
            Assert.AreEqual(expected.ProjectId, actual.fk_project);
            Assert.AreEqual(expected.OccurredOn, actual.occuredOn);
            Assert.AreEqual(expected.ConductedBy, actual.conductedBy);
            Assert.AreEqual(expected.EvidenceUrl, actual.uri_evidence);
        }

        [TestMethod]
        public void ShouldGetReviewsForProject()
        {
            ScrumLite.Data.IReviewStore store = this.mocks.DynamicMock<ScrumLite.Data.IReviewStore>();
            Guid projectId = Guid.NewGuid();
            ScrumLite.Data.Review[] expected = new ScrumLite.Data.Review[] {
                new ScrumLite.Data.Review() { id = Guid.NewGuid(), fk_project = projectId , occuredOn = DateTime.Now, conductedBy = "Auditor 1", uri_evidence = "http://some_url_review1.docx" },
                new ScrumLite.Data.Review() { id = Guid.NewGuid(), fk_project = projectId , occuredOn = DateTime.Now, conductedBy = "Auditor 2", uri_evidence = "http://some_url_review2.docx" }
            };

            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(store.RetrieveReviews(Guid.Empty))
                .Return(expected)
                .Callback(new Func<Guid, bool>(g => { return true; }));
            mocks.ReplayAll();

            LinqReviewsService service = new LinqReviewsService(store);

            Review[] actual = service.GetReviews(projectId.ToString());

            Assert.AreEqual(expected.Length, actual.Length);
            for (int i = 0; i < expected.Length; i++)
            {
                Assert.AreEqual(expected[i].id, actual[i].Id);
                Assert.AreEqual(expected[i].fk_project, actual[i].ProjectId);
                Assert.AreEqual(expected[i].occuredOn, actual[i].OccurredOn);
                Assert.AreEqual(expected[i].conductedBy, actual[i].ConductedBy);
                Assert.AreEqual(expected[i].uri_evidence, actual[i].EvidenceUrl);
            }
        }

        [TestMethod]
        public void ShouldGetAReview()
        {
            ScrumLite.Data.IReviewStore store = this.mocks.DynamicMock<ScrumLite.Data.IReviewStore>();
            Guid projectId = Guid.NewGuid();
            Guid reviewId = Guid.NewGuid();
            ScrumLite.Data.Review expected = new ScrumLite.Data.Review() { id = reviewId, fk_project = projectId, occuredOn = DateTime.Now, conductedBy = "Auditor 1", uri_evidence = "http://some_url_review1.docx" };

            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(store.RetrieveReview(Guid.Empty))
                .Return(expected)
                .Callback(new Func<Guid, bool>(g => { return true; }));
            mocks.ReplayAll();

            LinqReviewsService service = new LinqReviewsService(store);

            Review actual = service.GetReview(reviewId.ToString());

            Assert.AreEqual(expected.id, actual.Id);
            Assert.AreEqual(expected.fk_project, actual.ProjectId);
            Assert.AreEqual(expected.occuredOn, actual.OccurredOn);
            Assert.AreEqual(expected.conductedBy, actual.ConductedBy);
            Assert.AreEqual(expected.uri_evidence, actual.EvidenceUrl);
        }

        [TestMethod]
        public void ShouldGetReviewsByWeek()
        {
            ScrumLite.Data.IReviewStore store = this.mocks.DynamicMock<ScrumLite.Data.IReviewStore>();
            Guid projectId = Guid.NewGuid();
            Dictionary<DateTime,int> expected = new Dictionary<DateTime,int>();
            expected.Add(DateTime.Today, 23);
            expected.Add(DateTime.Today.AddDays(1), 32);

            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(store.RetrieveDailyReviewCount(projectId))
                .Return(expected)
                .Callback(new Func<Guid, bool>(g => { return true; }));
            mocks.ReplayAll();

            LinqReviewsService service = new LinqReviewsService(store);

            Dictionary<int, int> actual = service.GetReviewsByWeek(projectId.ToString());

            Assert.IsNotNull(actual);
            Assert.AreEqual(1, actual.Count);
            Assert.AreEqual(55,actual[GetYearWeek(DateTime.Today)]);
        }

        private static int GetYearWeek(DateTime date)
        {
            CultureInfo invariant = CultureInfo.InvariantCulture;
            return invariant.Calendar.GetWeekOfYear(date,
                                   invariant.DateTimeFormat.CalendarWeekRule,
                                   invariant.DateTimeFormat.FirstDayOfWeek);
        }
    }
}
